﻿using System;
using System.Collections.Generic;
using System.Linq;
using SelfMadeMillionaire.Core.Entities;
using SelfMadeMillionaire.Core.Enums;
using SelfMadeMillionaire.Core.Repositories;
using SelfMadeMillionaire.Core.Services;

namespace SelfMadeMillionaire.BLL.Services
{
	public class MailingListService : IMailingListService
	{
		private readonly IEmailMessageRepository _emailMessageRepository;
		private readonly IEmailService _emailService;
        IPublicationRepository publicationRepository;
        INewsletterRepository newsletterRepository;
        private readonly IEmailMessageSendRepository _emailMessageSendRepository;

        public MailingListService(IEmailMessageRepository emailMessageRepository, IEmailService emailService, IPublicationRepository publicationRepository, INewsletterRepository newsletterRepository, IEmailMessageSendRepository emailMessageSendRepository)
		{
			_emailMessageRepository = emailMessageRepository;
			_emailService = emailService;
            _emailMessageSendRepository = emailMessageSendRepository;
            this.publicationRepository = publicationRepository;
            this.newsletterRepository = newsletterRepository;
		}

		public IEnumerable<Subscriber> GetSubscribers(string firstName, string lastName, ProductType? selectedProduct,
			string email)
		{
			IEnumerable<Subscriber> subscribers = _emailMessageRepository.GetSubscribers();

			return subscribers.Where(x => (string.IsNullOrWhiteSpace(firstName) ? true : x.FirstName.ToLower().Contains(firstName.ToLower())) &&
                                          (string.IsNullOrWhiteSpace(lastName) ? true : x.LastName.ToLower().Contains(lastName.ToLower())) &&
                                          (string.IsNullOrWhiteSpace(email) ? true : x.Email.ToLower().Contains(email.ToLower())) &&
			                              (x.ProductType ==
			                               (selectedProduct.HasValue ? (byte) selectedProduct.Value : x.ProductType) ||
			                               ((x.ProductType & (byte) ProductType.SelfAndMaggies) == x.ProductType)
				                              ) &&
			                              x.Status == (byte) StatusType.Active);
		}

        public IEnumerable<Subscriber> GetSubscribersTester()
        {
            IEnumerable<Subscriber> subscribers = _emailMessageRepository.GetSubscribers();
            return subscribers.Where(x => (x.TesterAccount) &&
                                          x.Status == (byte)StatusType.Active);
        }

		public void Unsubscribe(string email)
		{
			Subscriber subscriber = _emailMessageRepository.GetSubscriber(email);
			if (subscriber != null)
			{
				subscriber.Status = (byte) StatusType.Deleted;
				subscriber.UnsubscribeDate = DateTime.Now;
				_emailMessageRepository.Commit();
			}
		}

        void FindAndUpdatePublicationLevel(EmailMessage msg, SubscriptionType level)
        {
            var pub = publicationRepository.GetAll().Where(p => p.EmailMessage != null && p.EmailMessage.ID == msg.ID).FirstOrDefault();
            if (pub != null)
            {
                pub.MinAccessLevel = (byte)level;
            }
            else
            {
                var news = newsletterRepository.GetAll().Where(p => p.EmailMessage != null && p.EmailMessage.ID == msg.ID).FirstOrDefault();
                if (news != null)
                {
                    news.MinAccessLevel = (byte)level;
                }
            }
        }

        DateTime GetPublicationDate(EmailMessage msg)
        {
            var pub = publicationRepository.GetAll().Where(p => p.EmailMessage != null && p.EmailMessage.ID == msg.ID).FirstOrDefault();
            if (pub != null)
            {
                return pub.Date;
            }
            else
            {
                var news = newsletterRepository.GetAll().Where(p => p.EmailMessage != null && p.EmailMessage.ID == msg.ID).FirstOrDefault();
                if (news != null)
                {
                    return news.Date;
                }
                else
                {
                    return DateTime.Now.AddYears(-1);
                }
            }
        }

		public bool SendMailingList()
		{
            IEnumerable<EmailMessage> emailMessages =
                _emailMessageRepository.GetAll().Where(x =>
                    x.SendMeToFreeMMMSubscribers()
                    || x.SendMeToFreeSMMSubscribers()
                    || x.SendMeToSilverSubscribers()
                    || x.SendMeToGoldSubscribers()
                    || x.SendMeToPlatinumSubscribers());

			IEnumerable<Subscriber> subscribers =
				_emailMessageRepository.GetSubscribers().Where(s => s.Status == (byte) StatusType.Active && s.Email.Contains("@"));

			bool returnStatus = true;


            List<string> pushKeys = new List<string>();
            foreach (EmailMessage msg in emailMessages.ToList())
			{
                // SMM-425: Sending program should never send publications over 2 weeks old.
                var d = GetPublicationDate(msg);
                if (DateTime.Now.AddDays(-14) > d)
                {
                    continue;
                }
                //

                string alertText = "";
                var newsletter = newsletterRepository.GetAll().Where(p => p.EmailMessage != null && p.EmailMessage.ID == msg.ID).FirstOrDefault();
                if (newsletter != null)
                {
                    if (newsletter.IssueType.Title == "Order Alert")
                    {
                        alertText = "You have a new order alert";
                    }
                    else if (newsletter.IssueType.Title == "Trade Alert")
                    {
                        alertText = "You have a new trade alert";
                    }
                }

                List<string> subs = new List<string>();
                
                if (msg.SendMeToFreeMMMSubscribers())
                {
                    foreach (var s in subscribers.Where(s => s.IsFreeMMMSubscriber()))
                    {
                        subs.Add(s.Email);
                        if (!string.IsNullOrEmpty(alertText))
                            pushKeys.AddRange(s.UserSessions.Select(ss => ss.DeviceToken + ";" + alertText));
                    }
                }
                else
                {
                    if (msg.SendMeToFreeSMMSubscribers())
                    {
                        foreach (var s in subscribers.Where(s => s.IsFreeSMMSubscriber()))
                        {
                            subs.Add(s.Email);
                            if (!string.IsNullOrEmpty(alertText))
                                pushKeys.AddRange(s.UserSessions.Select(ss => ss.DeviceToken + ";" + alertText));
                        }

                        FindAndUpdatePublicationLevel(msg, SubscriptionType.Free);
                    }
                    
                    if (msg.SendMeToSilverSubscribers())
                    {
                        foreach (var s in subscribers.Where(s => s.IsSilverSubscriber()))
                        {
                            subs.Add(s.Email);
                            if (!string.IsNullOrEmpty(alertText))
                                pushKeys.AddRange(s.UserSessions.Select(ss => ss.DeviceToken + ";" + alertText));
                        }

                        FindAndUpdatePublicationLevel(msg, SubscriptionType.Silver);
                    }
                    
                    if (msg.SendMeToGoldSubscribers())
                    {
                        foreach (var s in subscribers.Where(s => s.IsGoldSubscriber()))
                        {
                            subs.Add(s.Email);
                            if (!string.IsNullOrEmpty(alertText))
                                pushKeys.AddRange(s.UserSessions.Select(ss => ss.DeviceToken + ";" + alertText));
                        }

                        FindAndUpdatePublicationLevel(msg, SubscriptionType.Gold);
                    }

                    if (msg.SendMeToPlatinumSubscribers())
                    {
                        foreach (var s in subscribers.Where(s => s.IsPlatinumSubscriber()))
                        {
                            subs.Add(s.Email);
                            if (!string.IsNullOrEmpty(alertText))
                                pushKeys.AddRange(s.UserSessions.Select(ss => ss.DeviceToken + ";" + alertText));
                        }

                        FindAndUpdatePublicationLevel(msg, SubscriptionType.Platinum);
                    }
                }

                foreach (var s in subs)
                {
                    List<EmailMessageSend> emsList = _emailMessageSendRepository.GetAll().Where(x => x.EmailTo == s && x.EmailMessage == msg).ToList();
                    if (emsList.Count() > 0)
                        continue;

                    var sent = _emailService.SendAlerts(s, msg.Title, msg.Body);
                    //var sent = true;
                    
                    EmailMessageSend ems = new EmailMessageSend();
                    ems.SendDate = DateTime.Now;
                    ems.EmailTo = s;
                    ems.EmailMessage = msg;
                    ems.Status = (byte)(sent ? 1 : 0);
                    _emailMessageSendRepository.Add(ems);
                    _emailMessageSendRepository.Commit();

                    if (msg.SendMeToFreeMMMSubscribers())
                    {
                        msg.FreeSendStatus = sent ? (byte)SendStatus.Success : (byte)SendStatus.Fail;
                    }
                    else
                    {
                        if (msg.SendMeToFreeSMMSubscribers())
                        {
                            msg.FreeSendStatus = sent ? (byte)SendStatus.Success : (byte)SendStatus.Fail;
                        }
                        else if (msg.SendMeToSilverSubscribers())
                        {
                            msg.SilverSendStatus = sent ? (byte)SendStatus.Success : (byte)SendStatus.Fail;
                        }
                        else if (msg.SendMeToGoldSubscribers())
                        {
                            msg.GoldSendStatus = sent ? (byte)SendStatus.Success : (byte)SendStatus.Fail;
                        }
                        else if (msg.SendMeToPlatinumSubscribers())
                        {
                            msg.PlatinumSendStatus = sent ? (byte)SendStatus.Success : (byte)SendStatus.Fail;
                        }
                    }
                }
			}

            pushKeys = pushKeys.Distinct().ToList();
            foreach (var item in pushKeys)
            {
                string[] items = item.Split(';');
                if (items[0].Length > 64)
                {
                    NotificationHelper.Instance.SendAndroidNotification(item, string.Format("{\"Message\":\"{0}\"}", items[1]));
                }
                else
                {
                    NotificationHelper.Instance.SendAppleNotification(item, items[1]);
                }
            }

            publicationRepository.Commit();
            newsletterRepository.Commit();
			_emailMessageRepository.Commit();
            
			return returnStatus;
		}
	    
	}
}